import {invoke} from "@tauri-apps/api/core";


export class SqliteDatabase {
  private readonly path: string;
  private isOpen: boolean;
  private columns: Array<string> = [];
  protected table: string;

  constructor(path: string, table: string) {
    this.path = path;
    this.isOpen = false;
    this.table = table;
  }

  filter(filter: string): boolean {
    const result: string[] = [];
    const reg = /(\w+)\s*=\s*['"]?(.*?)['"]?/g
    let match;
    while ((match = reg.exec(filter)) !== null) {
      result.push(match[1]);
    }
    return result.filter(item => !this.columns.includes(item)).length <= 0;
  }

  public async open(): Promise<boolean> {
    if (this.isOpen) return false;
    await invoke("plugin:sqlite|open", { path: this.path });
    this.isOpen = true;
    return true;
  }

  public async close(): Promise<boolean> {
    if (!this.isOpen) return false;
    await invoke("plugin:sqlite|close", { path: this.path });
    this.isOpen = false;
    return true;
  }

  async getColumns(): Promise<void> {
    if (!this.isOpen) return ;
    this.columns = await invoke("plugin:sqlite|get_columns", { path: this.path, table: this.table });
  }

  public async execute(sql: string): Promise<number> {
    if (!this.isOpen) return -1;
    return invoke("plugin:sqlite|execute", { path: this.path, sql: sql });
  }

  public async query(filter: string = '', columns: [] = []): Promise<Array<Object>> {
    if (this.columns.length === 0) {
      await this.getColumns();
    }
    if (filter !== '' && !this.filter(filter)) return ['error'];
    if (!this.isOpen) return ['error'];
    return invoke("plugin:sqlite|query", { path: this.path, table: this.table, filter: filter, columns: columns });
  }

  public async insert(data: Object): Promise<number> {
    if (this.columns.length === 0) {
      await this.getColumns();
    }
    const keys = Object.keys(data);
    if (keys.filter(item => !this.columns.includes(item)).length > 0) return -1;
    if (!this.isOpen) return -2;
    return invoke("plugin:sqlite|insert", { path: this.path, table: this.table, data: data })
  }

  public async update(data: object, filter: string = ''): Promise<number> {
    if (this.columns.length === 0) {
      await this.getColumns();
    }
    if (filter !== '' && !this.filter(filter)) return -2;
    if (!this.isOpen) return -1;
    return invoke("plugin:sqlite|update", { path: this.path, table: this.table, data: data, filter: filter })
  }

  public async delete(filter: string = ''): Promise<number> {
    if (this.columns.length === 0) {
      await this.getColumns();
    }
    if (filter !== '' && !this.filter(filter)) return -2;
    if (!this.isOpen) return -1;
    return invoke("plugin:sqlite|delete", { path: this.path, table: this.table, filter: filter })
  }
}
